
/*-----------------------------------------------------------------------------\
|                          ChipCFlow Block2Code V1.0                           |
|                                                                              |
| Desenvolvedor: Felipe Simões Lage Gomes Duarte                               |
| Orientador: Prof. Dr. Jorge Luiz e Silva                                     |
| Supervisor: Bruno de Abreu Silva                                             |
|	      Joelmir José Lopes                                               |
|                                                                              |
| Main Project: ChipCflow                                                      |
| Período: Agosto de 2009 a Julho de 2010                                      |
| Codigo: Barramento.java                                                      |
| Versão da IDE: NetBeans IDE 6.8 (Build 200912041610)                         |
| Java: 1.6.0_18; Java HotSpot(TM) Client VM 16.0-b13                          |
| Sistema Operacional: Windows 7 versão 6.1 executando em x86; pt_BR           |
|                                                                              |
|             O presente trabalho foi realizado com apoio do CNPq              |
|   Conselho Nacional de Desenvolvimento Científico  e Tecnológico - Brasil    |
\-----------------------------------------------------------------------------*/
package components;//Nome do pacote de dados.

//declaraçao das classes importadas
import java.awt.BasicStroke;
import java.awt.Color;
import javax.swing.JPanel;
import java.awt.Graphics2D;
import java.awt.Point;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import view.Opcoes;

public class Barramento extends JPanel implements Components, Serializable {

  private int indice;
  private ArrayList<Point> Pontos;//vetor contendo os pontos do(s) segmento(s) de reta
  private String Name;//nome do conector
  private Conector Ci;
  private Conector Cf;
  private static int numInstancia = 0;


  /*----- Construtor da classe Barramento -----*/
  public Barramento(int x, int y) {
    Pontos = new ArrayList<Point>();
    Pontos.clear();
    add(x, y);
    add(x, y);
    Name = null;
    Ci = new Conector(Conector.BARRAMENTO, Pontos.get(0));
    Cf = new Conector(Conector.BARRAMENTO, Pontos.get(1));
  }

  /****************************  Getter & Setter  ****************************/
  public void add(Point P) {
    Pontos.add(P);
    Cf.setPoint(P);
  }

  public void add(int x, int y) {
    Point Aux = new Point();
    Aux.x = x;
    Aux.y = y;
    Pontos.add(Aux);
  }

  public void setBegin(int x, int y) {
    Ci.setCoordenada(x, y);
  }

  public Point getBegin() {
    return Ci.getPoint();
  }

  public void setEnd(int x, int y) {
    Cf.setCoordenada(x, y);
  }

  public Point getEnd() {
    return Cf.getPoint();
  }

  @Override
  public String getName() {
    return Name;
  }

  public void setConectorName(String Name) {
    this.Name = Name;
  }

  public void updateName() {
    this.Name = "conexao" + Integer.toString(numInstancia);
    numInstancia++;
  }

  public int getCiX() {
    return (Ci.getX());
  }

  public int getCiY() {
    return (Ci.getY());
  }

  public int getCfX() {
    return (Cf.getX());
  }

  public int getCfY() {
    return (Cf.getY());
  }

  public void setCiX(int x) {
    Ci.setX(x);
  }

  public void setCiY(int y) {
    Ci.setY(y);
  }

  public void setCfX(int x) {
    Cf.setX(x);
  }

  public void setCfY(int y) {
    Cf.setY(y);
  }

  public int getIndice() {
    return indice;
  }

  public void setIndice(int indice) {
    this.indice = indice;
  }

  public Conector getCf() {
    return Cf;
  }

  public void setCf(Conector Cf) {
    Pontos.get(Pontos.size() - 1).setLocation(Cf.getX(), Cf.getY());
    this.Cf = Cf;
  }

  public Conector getCi() {
    return Ci;
  }

  public void setCi(Conector Ci) {
    Pontos.get(0).setLocation(Ci.getX(), Ci.getY());
    this.Ci = Ci;
  }

  public int getPontosSize() {
    return Pontos.size();
  }

  public void conectCi(int x, int y, int indiceConected) {
    Ci.conect(x, y, indiceConected);
  }

  public void conectCf(int x, int y, int indiceConected) {
    Cf.conect(x, y, indiceConected);
  }

  /*
  Des.: Dado o espaço grafico, desenha o conector.
  Pre.: espaço graficoa ser desenhado.
  Pos.: desenha o conector no espaço grafico.
   */
  public void desenha(Graphics2D g) {
    int x1 = Ci.getX(),
            y1 = Ci.getY(),
            x2 = Cf.getX(),
            y2 = Cf.getY();
    Color Cor = Color.BLACK;//set cor do conector
    g.setColor(Cor);//set cor do objeto
    g.setStroke(new BasicStroke(1));//set espessura da linha

    for (int i = 1; i < Pontos.size(); i++) {//Percorre vetor de pontos.
      Point P1 = Pontos.get(i - 1);//ponto atrasado
      Point P2 = Pontos.get(i);//ponto atual
      g.drawLine(P1.x, P1.y, P1.x, P2.y);//desenha segmento de reta de P1 a P2
      g.drawLine(P1.x, P2.y, P2.x, P2.y);//desenha segmento de reta de P1 a P2
    } //se ponto inicial ou o ponto final esta conectado a alguma barramento de um

    //operador, desenha uma pequena circuferencia nas extremidade
    if (Ci.isConected()) {//se o ponto inicial esta conectado
      //desenha uma pequena circuferencia
      g.fillOval(Ci.getX() - 3, Ci.getY() - 3, 6, 6);
    }
    if (Cf.isConected()) {//se o ponto final esta conectado
      //desenha uma pequena circuferencia
      g.fillOval(Cf.getX() - 3, Cf.getY() - 3, 6, 6);
    }
  }

  /*
  Des.: dado uma coordenada e uma precisao, o metodo calcula se a distancia do ponto
   *    ate a reta e menor que a precisao.
  Pre.: A coordenada (x,y) e uma precisao.
  Pos.: retorna se a coordenada esta a uma distancia da reta menor que a precisao.
   */
  public boolean procuraForma(int x, int y) {
    int p = Opcoes.getInstance().getPrecisao();
    Point P1, P2; //pontos delimitando o segmento de reta
    double m;//coeficiente angular
    int XM, YM, Xm, Ym;//coordenadas da area produzida pelo segmento de reta
    //percorre o vetor de pontos

    for (int i = 1; i < Pontos.size(); i++) {
      //dois pontos determinam uma reta
      P1 = Pontos.get(i - 1);//pega o ponto1
      P2 = Pontos.get(i);//pega o ponto2

      //XM e YM = coordenadas maiores
      //Xm e Ym = coordenadas menores
      XM = (int) P1.getX();
      YM = (int) P1.getY();
      Xm = (int) P2.getX();
      Ym = (int) P2.getY();
      //se Xm for maior que XM troque

      if (Xm > XM) {
        int aux = Xm;
        Xm = XM;
        XM = aux;
      }
      //se Ym for maior que YM troque
      if (Ym > YM) {
        int aux = Ym;
        Ym = YM;
        YM = aux;
      } //delimita o segmento de reta
      if ((x >= Xm - p) & (x <= XM + p) & (y >= Ym - p) & (y <= YM + p)) {
        //se delta(Y) = 0 entao coeficiente angular = 0
        if ((P2.getY() - P1.getY()) == 0) {
          //verifica se a distancia do click até a reta é menor que a precisao
          if (Math.abs(Math.round(y - P1.getY())) <= p) {
            return true;//se sim achou
          }
        } else if ((P2.getX() - P1.getX()) == 0) {//se delta(X) = 0 entao coeficiente angular = infinito
          //verifica se a distancia do click até a reta é menor que a precisao
          if (Math.abs(Math.round(x - P1.getX())) <= p) {
            return true;//se sim achou
          }
        } else {//se delta(X) e delta(Y) = 0 enta coeficiente angular = delta(Y)/delta(X)
          //calcula o coeficiente angular da reta formada pelos pontos 1 e 2
          m = (P2.getY() - P1.getY()) / (P2.getX() - P1.getX());
          //calcula se a distancia entre o ponto e a reta é menor que a precisao
          if ((Math.abs(y + (x * (-m)) + (-P1.getY() + (m * P1.getX()))) / Math.sqrt(1 + (m * m))) < p) {
            return true;//se sim achou
          }
        }
      }
    }
    return false;
  }

  public void mover(int Dx, int Dy) {
    Iterator<Point> it = this.Pontos.iterator();
    while (it.hasNext()) {
      it.next().translate(Dx, Dy);
    }
  }
}
